package com.turing.procedure.service.task.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.mysql.cj.x.protobuf.MysqlxCrud;
import com.turing.common.entity.Context;
import com.turing.common.entity.UserToken;
import com.turing.common.response.CommonCode;
import com.turing.common.response.PageBean;
import com.turing.common.response.ResponseCode;
import com.turing.common.response.ResponseVO;
import com.turing.common.util.*;
import com.turing.procedure.client.draw.DrawInnerService;
import com.turing.procedure.client.template.TemplateClient;
import com.turing.procedure.dao.task.TaskRecordMapper;
import com.turing.procedure.enums.ProcedureResultCode;
import com.turing.procedure.enums.TaskStatusEnum;
import com.turing.procedure.model.domain.task.TaskRecord;
import com.turing.procedure.model.domain.task.TaskRecordDto;
import com.turing.procedure.service.task.TaskRecordService;
import com.turing.procedure.utils.UploadUtil;
import com.turing.procedure.vo.in.ReviewContentVo;
import com.turing.procedure.vo.in.TaskRecordVo;
import com.turing.procedure.vo.in.TemplateVo;
import com.turing.procedure.vo.out.FileListVO;
import com.turing.procedure.vo.in.FileSearchVO;
import com.turing.procedure.vo.out.FilePageBean;
import com.turing.procedure.vo.out.ReviewedFileListVO;
import com.turing.procedure.vo.out.ReviewingFileListVO;
import org.apache.commons.logging.LogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.lang.reflect.Array;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class TaskRecordServiceImpl extends ServiceImpl<TaskRecordMapper, TaskRecord> implements TaskRecordService {

    @Autowired
    private TaskRecordMapper taskRecordMapper;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private TemplateClient templateClient;

    @Autowired
    private DrawInnerService drawInnerService;

    private static Logger logger = LoggerFactory.getLogger(TaskRecordServiceImpl.class);

    @Override
    public FilePageBean<FileListVO> getTaskRecordList(FileSearchVO searchVO) {

        List<FileListVO> resultList = new ArrayList<>();
        QueryWrapper<TaskRecord> queryWrapper = new QueryWrapper<>();
        //queryWrapper.orderByDesc("task_sn");
        queryWrapper.orderByDesc("created_time");
        queryWrapper.eq("is_del",0);

        if (!StringUtils.isEmpty(searchVO.getSearchName())) {
            queryWrapper.like("task_name",searchVO.getSearchName());
        }

        if (!StringUtils.isEmpty(searchVO.getTemplateId()) && !searchVO.getTemplateId().equals("-1")) {
            queryWrapper.eq("template_id",searchVO.getTemplateId());
        }

        if (!StringUtils.isEmpty(searchVO.getDateBegin()) || !StringUtils.isEmpty(searchVO.getDateEnd())) {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date begin;
            Date end;
            try {
                begin = simpleDateFormat.parse(searchVO.getDateBegin() + " 00:00:00");
                queryWrapper.ge("upload_time",begin);
            } catch (Exception e) {
                e.printStackTrace();
            }

            try {
                end = simpleDateFormat.parse(searchVO.getDateEnd() + " 23:59:59");
                queryWrapper.le("upload_time",end);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

        UserToken tokenContext = Context.getTokenContext();
        if(Tools.isNotEmpty(tokenContext.getTemplates())){
            Map<String, Integer> templates = tokenContext.getTemplates();
            Set<String> tids = templates.keySet();
            queryWrapper.in("template_id",new ArrayList<>(tids));
        }

        //数据权限
        Map<String, List<Integer>> dataPrivilege = tokenContext.getDataPrivilege();

        List<Integer> dataRoleIds = dataPrivilege.get("dataRoleIds");

        List<Integer> ableUserIds = dataPrivilege.get("able");
        List<Integer> disUserIds = dataPrivilege.get("disable");
        if( dataRoleIds != null && ableUserIds !=null){//个人可见
            queryWrapper.and(qr ->
                    qr.in("created_by", ableUserIds).
                            or().
                            in("created_by_role", dataRoleIds)
            );

        }else{
            if(dataRoleIds !=null){//角色可见
                queryWrapper.in("created_by_role",dataRoleIds);
            }
            if(disUserIds !=null){//所有人可见，除admin
                queryWrapper.notIn("created_by",disUserIds);
            }

        }
        logger.info(tokenContext.getUserCode()+"用户的数据权限,dataPrivilege="+dataPrivilege);

        List<Integer> prepared = Collections.singletonList(0);
        List<Integer> pending = Arrays.asList(1,2);
        List<Integer> finished = Arrays.asList(3,4,5);
        List<Integer> failed = Collections.singletonList(10);

        Integer status = searchVO.getStatus();
        if ( status != null && status != -1 ) {
            queryWrapper.in("status",transStatus(status));
        }
        QueryWrapper<TaskRecord> copyWrapper = (QueryWrapper<TaskRecord>)ObjectUtils.deepClone(queryWrapper);
        QueryWrapper<TaskRecord> pendingWrapper = (QueryWrapper<TaskRecord>)ObjectUtils.deepClone(queryWrapper);
        QueryWrapper<TaskRecord> completedWrapper = (QueryWrapper<TaskRecord>)ObjectUtils.deepClone(queryWrapper);
        QueryWrapper<TaskRecord> failedWrapper = (QueryWrapper<TaskRecord>)ObjectUtils.deepClone(queryWrapper);

        if (Tools.isNotEmpty(searchVO.getType())) {
             if (searchVO.getType() == 1) {
                queryWrapper.in("status",prepared);
             } else if (searchVO.getType() == 2) {
                queryWrapper.in("status",pending);
             } else if (searchVO.getType() == 3) {
                 queryWrapper.in("status", finished);
             }else if (searchVO.getType() == 4) {
                 queryWrapper.in("status", failed);
             }
        }

        int sumCount = count(copyWrapper);
        copyWrapper.in("status",prepared);
        int prepareCount = count(copyWrapper);

        pendingWrapper.in("status",pending);
        int pendingCount = count(pendingWrapper);

        completedWrapper.in("status",finished);
        int completedCount = count(completedWrapper);

        failedWrapper.in("status",failed);
        int failedCount = count(failedWrapper);

        if (searchVO.getIsPage() == 1) {
            PageHelper.startPage(searchVO.getPageIndex(),searchVO.getPageSize());
        }

        List<TaskRecord> taskRecords = list(queryWrapper);
        if (taskRecords != null && taskRecords.size() > 0) {
            for (TaskRecord taskRecord : taskRecords) {
                FileListVO reviewedFileListVO = new FileListVO();
                reviewedFileListVO.copy(taskRecord);
                reviewedFileListVO.setDrawStatus(getDrawStatus(taskRecord.getStatus()));
                reviewedFileListVO.setReviewStatus(getReviewStatus(taskRecord.getStatus()));
                resultList.add(reviewedFileListVO);
            }
        }
        long l = count(queryWrapper);
        FilePageBean<FileListVO> pageBean = searchVO.getIsPage() == 1 ? new FilePageBean<>(searchVO.getPageIndex(),searchVO.getPageSize(),(int)l,prepareCount,pendingCount,completedCount,failedCount,sumCount) : new FilePageBean<>();
        pageBean.setItems(resultList);
        return pageBean;

    }

    private Integer getDrawStatus(Integer status) {
        switch (status){
            case 1:
            case 2:
                return 1;
            case 3:
            case 4:
            case 5:
                return 2;
            case 10:
                return 10;
            default:
                return 0;
        }
    }

    private Integer getReviewStatus(Integer status) {
        switch (status){
            case 0:
            case 1:
            case 2:
                return -1;
            case 4:
                return 1;
            case 5:
                return 2;
            case 10:
                return 10;
            default:
                return 0;
        }
    }

    private List<Integer> transStatus(Integer status) {

        switch (status){
            case 0:
                return Collections.singletonList(0);
            case 1:
                return Arrays.asList(1,2);
            case 2:
            case 3:
                return Collections.singletonList(3);
            case 10:
                return Collections.singletonList(10);
            case 4:
                return Collections.singletonList(4);
            case 5:
                return Collections.singletonList(5);
            default:
                return new ArrayList<>();
        }

    }

    @Override public ResponseVO<ReviewContentVo> batchGetReviewContent(List<String> taskSns){
        //用户id
        Integer userId = Context.getTokenContext().getUserId();
        //用户登录账号
        String userCode = Context.getTokenContext().getUserCode();
        QueryWrapper<TaskRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("task_sn",taskSns).eq("is_del",0);
        List<TaskRecord> taskRecordList = list(queryWrapper);

        //保证有序
        Map<String, TaskRecord> taskRecordMap = taskRecordList.stream().collect(Collectors.toMap(TaskRecord:: getTaskSn, taskRecord -> taskRecord));
        taskRecordList.clear();
        taskSns.forEach(taskSn -> {
            taskRecordList.add(taskRecordMap.get(taskSn));
        });
        List<String> taskNameList = new ArrayList<>(taskRecordList.size());
        taskRecordList.forEach(taskRecord -> {
            AssertUtil.isTrue(taskRecord.getStatus() != 3 && taskRecord.getStatus() != 4 && taskRecord.getStatus() != 5,"只有待审核状态的任务才能进行审核");
            //AssertUtil.isTrue(Tools.isNotEmpty(taskRecord.getReviewer()) && !Tools.equals(taskRecord.getReviewer(),userId), ProcedureResultCode.NOT_YOUR_TASK);
            AssertUtil.isEmpty(taskRecord.getTaskSn(),ProcedureResultCode.NO_MORE_TASK);
        });

        //批量入库
        Boolean result = transactionTemplate.execute(transactionStatus -> {
            LocalDateTime date = LocalDateTime.now();
            UpdateWrapper<TaskRecord> updateWrapper = new UpdateWrapper<>();
            //过滤属性
            List<Integer> idList = new ArrayList<>(taskRecordList.size());
            taskRecordList.forEach(taskRecord -> {
                idList.add(taskRecord.getId());
                taskNameList.add(taskRecord.getTaskName());
            });
            //修改
            TaskRecord taskRecord = TaskRecord.builder().reviewer(userId)
                    .reviewTime(new Date())
                    //.updatedBy(userCode)
                    .build();
            taskRecord.setUpdatedTime(date);
            updateWrapper.in("id",idList);
            int updateResult = taskRecordMapper.update(taskRecord,updateWrapper);

            updateWrapper.eq("status",3);
            taskRecordMapper.update(TaskRecord.builder().status(4).build(),updateWrapper);

            if (updateResult != taskRecordList.size()) {
                transactionStatus.setRollbackOnly();
                return false;
            }
            return true;
        });

        return result != null && result ? ResponseUtil.success(ReviewContentVo.builder().url("/taskPage/elementsExtraction/examinePage").taskNameList(taskNameList).build())
                : ResponseUtil.create(CommonCode.FAIL);
    }


    @Override
    public boolean updateTaskStatus(Integer status,String taskSn){

        Log.info(">>>>> updating task status, taskSn  is " + taskSn + ", status is " + status);

        return lambdaUpdate().eq(TaskRecord::getTaskSn,taskSn).set(TaskRecord::getStatus,status).update();

    }

    @Override
    public boolean taskFailed(String taskSn, String errorMessage) {

        return lambdaUpdate().eq(TaskRecord::getTaskSn,taskSn)
                .set(TaskRecord::getStatus,TaskStatusEnum.FAILED.getCode())
                .set(TaskRecord::getErrorMessage,errorMessage).update();

    }

    @Override
    public List<TaskRecordVo> getTaskRecord(TaskRecordDto taskRecordDto) {

        QueryWrapper<TaskRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id","task_name","child_tasks","task_sn","child_task_sns","template_id","template_name","file_state","created_by")
                .eq(Tools.isNotEmpty(taskRecordDto.getTaskSn()),"task_sn",taskRecordDto.getTaskSn())
                .eq(Tools.isNotEmpty(taskRecordDto.getTaskName()),"task_name",taskRecordDto.getTaskName())
                .eq(Tools.isNotEmpty(taskRecordDto.getTemplateId()),"template_id",taskRecordDto.getTemplateId())
                .ge(Tools.isNotEmpty(taskRecordDto.getBeginTime()),"upload_time",taskRecordDto.getBeginTime())
                .le(Tools.isNotEmpty(taskRecordDto.getEndTime()),"upload_time",taskRecordDto.getEndTime())
                .in(Tools.isNotEmpty(taskRecordDto.getFileState()),"file_state",taskRecordDto.getFileState())
                .in(Tools.isNotEmpty(taskRecordDto.getTemplateIds()),"template_id",taskRecordDto.getTemplateIds());
        //查询结果。返回VO对象
        List<TaskRecord> taskRecords = list(queryWrapper);
        return taskRecords.stream().map(taskRecord -> {
            TaskRecordVo taskRecordVo = TaskRecordVo.builder().build();
            BeanUtils.copyProperties(taskRecord,taskRecordVo);
            return taskRecordVo;
        }).collect(Collectors.toList());

    }

    @Override
    public Boolean removeProcessTasks(List<String> taskIds){

        ResponseVO<Object> objectResponseVO = drawInnerService.removeBatch(taskIds);
        if(objectResponseVO.getCode().equals(ResponseCode.SUCCESS)){
            return remove(new LambdaQueryWrapper<TaskRecord>().in(TaskRecord::getTaskSn,taskIds));
        }else{
            return false;
        }

    }

    @Override
    public boolean finishReview(String taskSn) {


        LambdaQueryWrapper<TaskRecord> query = new LambdaQueryWrapper<>();
        query.eq(TaskRecord::getTaskSn,taskSn);
        TaskRecord update = new TaskRecord();

        List<TaskRecord> taskRecords = taskRecordMapper.selectList(query);
        if (Tools.isNotEmpty(taskRecords)) {
            TemplateVo templateVo = templateClient.getTemplateById(taskRecords.get(0).getTemplateId()).getData();
            //如果是自动审核，设置固定的审核人
            if (templateVo.getAutoAudit() == 1) {
                String templateId = "11".equals(templateVo.getType()) ? "11" : templateVo.getTemplateSn();
                update.setReviewerName(UploadUtil.getUploadName(templateId));
            } else {
                //非自动审核设置为当前用户
                update.setReviewerName(Context.getTokenContext().getUserCode());
            }
        }

        //        if ( version == 0 ) {
        //            update.setFileState( 5 );
        update.setReviewTime(new Date());
        //        }else if ( version == 1 ) {
        update.setStatus(TaskStatusEnum.REVIEWED.getCode());
        //        }

        //Integer taskId = reviewTaskService.getTaskIdBySn(taskSn);
        //TaskRecord taskRecord = taskRecordMapper.selectByPrimaryKey(taskId);
        //
        //SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //reviewTaskInnerService.writeReviewedResult(taskSn,simpleDateFormat.format(taskRecord.getUploadTime()));

        return update(update,query);

    }

    @Override
    public List<FileListVO> getPreviousAndNext(FileListVO fileListVO,Map<String, Integer> privileges) {

        UserToken tokenContext = Context.getTokenContext();
        Map<String, List<Integer>> dataPrivilege = tokenContext.getDataPrivilege();
        Integer userId = Context.getTokenContext().getUserId();
        List<Integer> statuses = Arrays.asList(3, 4, 5);
        List<FileListVO> result= new ArrayList<>(2);

        LambdaQueryChainWrapper<TaskRecord> nextWrapper = lambdaQuery().ge(TaskRecord::getTaskSn, fileListVO.getTaskSn())
                .in(TaskRecord::getTemplateId, privileges.keySet())
                .ne(TaskRecord::getTaskSn, fileListVO.getTaskSn())
                .in(TaskRecord::getStatus, statuses);

        //数据权限
        List<Integer> dataRoleIds = dataPrivilege.get("dataRoleIds");
        List<Integer> ableUserIds = dataPrivilege.get("able");
        List<Integer> disUserIds = dataPrivilege.get("disable");
        if( dataRoleIds != null && ableUserIds !=null){//个人可见
            nextWrapper.and(qr ->
                    qr.in(TaskRecord::getCreatedBy, ableUserIds).
                            or().
                            in(TaskRecord::getCreatedByRole, dataRoleIds)
            );
        }else{
            if(dataRoleIds !=null){//角色可见
                nextWrapper.in(TaskRecord::getCreatedByRole,dataRoleIds);
            }
            if(disUserIds !=null){//所有人可见，除admin
                nextWrapper.notIn(TaskRecord::getCreatedBy,disUserIds);
            }
        }

        TaskRecord nextRecord = nextWrapper.orderByAsc(TaskRecord::getTaskSn)
                .last("limit 1").one();
        if(nextRecord != null){
            FileListVO next = new FileListVO();
            next.setTaskSn(nextRecord.getTaskSn());
            next.setUploadTime(nextRecord.getUploadTime());
            next.setReviewStatus(getReviewStatus(nextRecord.getStatus()));
            result.add(next);
        }else{
            result.add(new FileListVO());
        }

        LambdaQueryChainWrapper<TaskRecord> prevWrapper = lambdaQuery().le(TaskRecord::getTaskSn, fileListVO.getTaskSn())
                .in(TaskRecord::getTemplateId, privileges.keySet())
                .ne(TaskRecord::getTaskSn, fileListVO.getTaskSn())
                .in(TaskRecord::getStatus, statuses);
        //数据权限
        if( dataRoleIds != null && ableUserIds !=null){//个人可见
            prevWrapper.and(qr ->
                    qr.in(TaskRecord::getCreatedBy, ableUserIds).
                            or().
                            in(TaskRecord::getCreatedByRole, dataRoleIds)
            );

        }else{
            if(dataRoleIds !=null){//角色可见
                prevWrapper.in(TaskRecord::getCreatedByRole,dataRoleIds);
            }
            if(disUserIds !=null){//所有人可见，除admin
                prevWrapper.notIn(TaskRecord::getCreatedBy,disUserIds);
            }
        }

        TaskRecord prevRecord =
                prevWrapper.orderByDesc(TaskRecord::getTaskSn)
                .last("limit 1").one();
        if(prevRecord != null){
            FileListVO prev = new FileListVO();
            prev.setTaskSn(prevRecord.getTaskSn());
            prev.setUploadTime(prevRecord.getUploadTime());
            prev.setReviewStatus(getReviewStatus(prevRecord.getStatus()));
            result.add(prev);
        }else{
            result.add(new FileListVO());
        }

        return result;

    }

}
